#!/usr/bin/env python
# -*- coding: utf-8; -*-
#
#
from google.appengine.ext import webapp
from google.appengine.ext.webapp import util
from google.appengine.api import memcache
from django.utils import simplejson
import logging

def fib(n):
    if n<0:
        logging.error('n must be >=0')
        return
    if n==1:
        return 1
    else:
        if n==0:
            return 0
        else:
            try:
                f = memcache.get(key=str(n))
            except Exception, E:
                logging.error("An error occurred: %s\n" % (str(E)))
            if f is not None:
                logging.info('Cache hit: f(%d)=%d' % (n, f))
            else:
                logging.info('Cache miss: getting f(%d)' % n)
                f = fib(n-1) + fib(n-2)
                try:
                    logging.info('Setting cache value: f(%d)=%d' % (n, f))
                    memcache.add(key=str(n), value=f)
                except Exception, E:
                    logging.error("An error occurred: %s\n" % (str(E)))
            return f

class FibonacciHandler(webapp.RequestHandler):
    def get(self,var):
        args = self.request.arguments()
        if 'input' in args:
            try:
                input = self.request.get('input')
                if input:
                    try:
                        n = int(input)
                        if n<0:
                            f = {'exception':'n must be >= 0'}
                        else:
                            f = {'result': fib(n)}
                        self.response.out.write(simplejson.dumps(f))
                    except Exception, E:
                        msg = 'Input "%s" is not an integer' % input
                        e = {'exception':msg}
                        self.response.out.write(simplejson.dumps(e))
                        logging.error(E)
                else:
                    msg = 'No input given!  Query must be of the form ?input=N' % input
                    e = {'exception':msg}
                    self.response.out.write(simplejson.dumps(e))
            except Exception, E:
                msg = 'Query must be of the form ?input=N'
                e = {'exception':msg}
                self.response.out.write(simplejson.dumps(e))
                logging.error(E)
        else:
            # no 'input' argument
            self.redirect("/index.html")

class MainHandler(webapp.RequestHandler):
    def get(self):
        self.response.out.write('<p>Will take one URL get parameter called input (e.g. <a href=http://fibkaj.appspot.com/?input=3>http://fibkaj.appspot.com/?input=3</a>), that is an integer, and return a payload containing a json response containing the Fibonacci number for that integer in the format {"result" : number}. Wrong inputs will return a json payload in the format {"exception" : "string that explains cause of the exception"}</p>')
        self.response.out.write("""<p>More examples:<br><li><a href=http://fibkaj.appspot.com/?input=-5>http://fibkaj.appspot.com/?input=-5</a>
<li><a href=http://fibkaj.appspot.com/?input=foo>http://fibkaj.appspot.com/?input=foo</a>
<li><a href=http://fibkaj.appspot.com/?input=20>http://fibkaj.appspot.com/?input=20</a><p>""")
        self.response.out.write('Based on an entry for Round I of the <a href=http://sites.google.com/site/lastcallforio2011/app-engine>App Engine challenge</a> for <a href=http://sites.google.com/site/lastcallforio2011/Home>Last Call for Google I/O</a><br>')
        self.response.out.write('Source code is available at <a href=http://code.google.com/p/fibonnaci-gae>Google Code</a>')
        
def main():
    application = webapp.WSGIApplication([('/index.html', MainHandler),
                                          ('(.*)', FibonacciHandler)
                                          ],
                                         debug=True)
    util.run_wsgi_app(application)


if __name__ == '__main__':
    main()
